package com.spsoft.vatoutinv.jobHandler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.leqidmz.param.QueryUploadInvoiceStatusParam;
import com.spsoft.core.model.leqidmz.response.QueryUploadInvoiceStatusVO;
import com.spsoft.einvoicetodmz.service.DmzApiClientService;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceDetails;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.VmsFullOutInvoiceDetailsService;
import com.spsoft.vms.redis.service.impl.InvoiceFileCreateVmsQueueServiceImpl;
import com.spsoft.vms.redis.service.impl.QueryUploadInvoiceVmsQueueServiceImpl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 查询数电票上传结果定时任务
 *
 * @author : chenxudong
 * @date : 2024/3/14 14:03
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class VmsUploadInvoiceQueryJob {

    public static final String LOG_MSG = "(查询数电票上传结果定时任务)";

    public static final String USER_NAME = "定时任务";

    private final DmzApiClientService dmzApiClientService;

    private final VmsFullOutInvoiceDetailsService invoiceDetailsService;

    private final QueryUploadInvoiceVmsQueueServiceImpl queryUploadInvoiceVmsQueue;

    private final InvoiceFileCreateVmsQueueServiceImpl invoiceFileCreateVmsQueue;

    @XxlJob("vmsUploadInvoiceQueryJobHandler")
    public ReturnT<String> vmsUploadInvoiceQueryJobHandler() {
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();
        XxlJobHelper.log("{}分片参数，当前分片序号：{}, 总分片数：{}", LOG_MSG, shardIndex, shardTotal);

        // 该定时任务使用分片广播模式，防止多个执行器同时执行造成redis队列压力过大，根据当前分片序号进行睡眠
        try {
            long time = (shardIndex + 1) * 500L;
            Thread.sleep(time);
            XxlJobHelper.log("{}分片序号：{}，睡眠{}ms完成", LOG_MSG, shardIndex, time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long start = System.currentTimeMillis();
        XxlJobHelper.log("{}开始执行", LOG_MSG);

        // 自定义队列获取数量
        String count = XxlJobHelper.getJobParam();
        if (StringUtils.isBlank(count)) {
            count = "100";
        }

        // 获取 查询发票上传结果延时队列中的受理流水号
        List<String> msgList = queryUploadInvoiceVmsQueue.getMessagesFromQueue(Integer.parseInt(count));
        boolean success = true;
        if (CollectionUtil.isNotEmpty(msgList)) {
            // 受理流水号去重
            Set<String> msgSet = new HashSet<>(msgList);
            for (String msg : msgSet) {
                String[] split = msg.split("-");
                String sllsh = split[0];
                String deptCode = split[1];
                int retryCount = Integer.parseInt(split[2]);
                try {
                    // 查询发票上传结果失败重试次数最大为3次
                    if (retryCount < 3) {
                        QueryUploadInvoiceStatusParam param = new QueryUploadInvoiceStatusParam();
                        param.setSllsh(sllsh);
                        param.setDeptCode(deptCode);
                        param.setCreateUser(USER_NAME);
                        Result<QueryUploadInvoiceStatusVO> result = dmzApiClientService.queryUploadInvoiceStatus(param, null);
                        if (ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
                            XxlJobHelper.log("{}受理流水号：{}，查询发票上传结果成功，出参：{}", LOG_MSG, sllsh, JSONObject.toJSONString(result));
                            List<QueryUploadInvoiceStatusVO.FapiaoStatus> resultList = result.getData().getResultList();
                            for (QueryUploadInvoiceStatusVO.FapiaoStatus invoiceStatus : resultList) {
                                // 判断乐企返回的上传结果
                                if (CommonEnum.UPLOAD_RESULT_00.getKey().equals(invoiceStatus.getStatus())) {
                                    // 上传成功
                                    LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_2.getKey())
                                            .set(VmsFullOutInvoiceDetails::getScjg, invoiceStatus.getMessage())
                                            .set(VmsFullOutInvoiceDetails::getUpdateTime, new Date())
                                            .set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME)
                                            .eq(VmsFullOutInvoiceDetails::getFphm, invoiceStatus.getFphm());
                                    invoiceDetailsService.update(updateWrapper);

                                    boolean flag = invoiceFileCreateVmsQueue.addMessageToQueue(invoiceStatus.getFphm());
                                    if (flag) {
                                        XxlJobHelper.log("{}发票号码：{}，上传成功，放到版式文件生成队列中", LOG_MSG, invoiceStatus.getFphm());
                                    }
                                } else if (CommonEnum.UPLOAD_RESULT_01.getKey().equals(invoiceStatus.getStatus())) {
                                    // 发票上传处理中
                                    LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_1.getKey())
                                            .set(VmsFullOutInvoiceDetails::getScjg, invoiceStatus.getMessage())
                                            .set(VmsFullOutInvoiceDetails::getUpdateTime, new Date())
                                            .set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME)
                                            .eq(VmsFullOutInvoiceDetails::getFphm, invoiceStatus.getFphm());
                                    invoiceDetailsService.update(updateWrapper);
                                    // 发票上传处理中，重新放回查询发票上传结果延时队列中
                                    String message = sllsh + "-" + deptCode + "-" + retryCount;
                                    boolean flag = queryUploadInvoiceVmsQueue.addMessageToQueue(message);
                                    if (flag) {
                                        XxlJobHelper.log("{}发票号码：{}，发票上传处理中，重新放回查询发票上传结果延时队列中", LOG_MSG, invoiceStatus.getFphm());
                                    }
                                } else if (CommonEnum.UPLOAD_RESULT_02.getKey().equals(invoiceStatus.getStatus())) {
                                    // 上传失败
                                    LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey())
                                            .set(VmsFullOutInvoiceDetails::getScjg, invoiceStatus.getMessage())
                                            .set(VmsFullOutInvoiceDetails::getUpdateTime, new Date())
                                            .set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME)
                                            .eq(VmsFullOutInvoiceDetails::getFphm, invoiceStatus.getFphm());
                                    invoiceDetailsService.update(updateWrapper);
                                    XxlJobHelper.log("{}发票号码：{}，上传失败，原因：{}", LOG_MSG, invoiceStatus.getFphm(), invoiceStatus.getMessage());
                                } else if (CommonEnum.UPLOAD_RESULT_03.getKey().equals(invoiceStatus.getStatus())) {
                                    // 重复上传，发票号码在乐企数据库已存在，修改为已上传
                                    LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_2.getKey())
                                            .set(VmsFullOutInvoiceDetails::getScjg, invoiceStatus.getMessage())
                                            .set(VmsFullOutInvoiceDetails::getUpdateTime, new Date())
                                            .set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME)
                                            .eq(VmsFullOutInvoiceDetails::getFphm, invoiceStatus.getFphm());
                                    invoiceDetailsService.update(updateWrapper);
                                    XxlJobHelper.log("{}发票号码：{}，重复上传，返回值：{}", LOG_MSG, invoiceStatus.getFphm(), invoiceStatus.getMessage());
                                } else {
                                    // 乐企返回未知状态
                                    LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey())
                                            .set(VmsFullOutInvoiceDetails::getScjg, invoiceStatus.getMessage())
                                            .set(VmsFullOutInvoiceDetails::getUpdateTime, new Date())
                                            .set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME)
                                            .eq(VmsFullOutInvoiceDetails::getFphm, invoiceStatus.getFphm());
                                    invoiceDetailsService.update(updateWrapper);
                                    XxlJobHelper.log("{}发票号码：{}，乐企返回未知状态，返回值：{}", LOG_MSG, invoiceStatus.getFphm(), JSONObject.toJSONString(invoiceStatus));
                                }
                            }
                        } else {
                            XxlJobHelper.log("{}查询发票上传结果失败：{}", LOG_MSG, result.getMessage());
                            // 更新发票的上传状态
                            LambdaQueryWrapper<VmsFullOutInvoiceDetails> queryWrapper = new LambdaQueryWrapper<>();
                            queryWrapper.eq(VmsFullOutInvoiceDetails::getQydjid, deptCode);
                            queryWrapper.eq(VmsFullOutInvoiceDetails::getSllsh, sllsh);
                            // 发票上传时间与开票时间间隔应当小于48小时
                            // 发票上传结果只能在发票上传后12小时内查询，如果超过12小时只能重新上传发票再获取上传结果
                            String kprq = DateUtil.format(DateUtil.offsetDay(new Date(), -3), CommonConstant.DATE_FORMAT_14);
                            queryWrapper.apply("KPRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", kprq);
                            queryWrapper.orderByAsc(VmsFullOutInvoiceDetails::getFoidid);
                            List<VmsFullOutInvoiceDetails> invoiceList = invoiceDetailsService.list(queryWrapper);
                            if (CollectionUtil.isNotEmpty(invoiceList)) {
                                for (VmsFullOutInvoiceDetails invoice : invoiceList) {
                                    // 状态还是为上传中
                                    LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                                    if (retryCount == 2) {
                                        // 如果是最后一次进行重试，将状态改为上传失败
                                        updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey());
                                    } else {
                                        updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_1.getKey());
                                    }
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getScjg, result.getMessage());
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getUpdateTime, new Date());
                                    updateWrapper.set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME);
                                    updateWrapper.eq(VmsFullOutInvoiceDetails::getFoidid, invoice.getFoidid());
                                    invoiceDetailsService.update(updateWrapper);
                                }
                            }
                            if (retryCount < 2) {
                                // 查询发票上传结果失败，重新放回查询发票上传结果延时队列中
                                String message = sllsh + "-" + deptCode + "-" + (retryCount + 1);
                                boolean flag = queryUploadInvoiceVmsQueue.addMessageToQueue(message);
                                if (flag) {
                                    XxlJobHelper.log("{}查询发票上传结果失败，重新放回查询发票上传结果延时队列中", LOG_MSG);
                                }
                            }
                            success = false;
                        }
                    } else {
                        XxlJobHelper.log("{}受理流水号：{}，查询发票上传结果失败重试次数：{},不再处理", LOG_MSG, sllsh, retryCount);
                        success = false;
                    }
                } catch (Exception e) {
                    XxlJobHelper.log("{}查询发票上传结果失败：{}", LOG_MSG, e.getMessage());
                    // 查询发票上传结果失败，重新放回查询发票上传结果延时队列中
                    String message = sllsh + "-" + deptCode + "-" + (retryCount + 1);
                    boolean flag = queryUploadInvoiceVmsQueue.addMessageToQueue(message);
                    if (flag) {
                        XxlJobHelper.log("{}查询发票上传结果失败，重新放回查询发票上传结果延时队列中", LOG_MSG);
                    }
                    // 更新发票的上传状态
                    LambdaQueryWrapper<VmsFullOutInvoiceDetails> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(VmsFullOutInvoiceDetails::getQydjid, deptCode);
                    queryWrapper.eq(VmsFullOutInvoiceDetails::getSllsh, sllsh);
                    // 发票上传时间与开票时间间隔应当小于48小时
                    // 发票上传结果只能在发票上传后12小时内查询，如果超过12小时只能重新上传发票再获取上传结果
                    String kprq = DateUtil.format(DateUtil.offsetDay(new Date(), -3), CommonConstant.DATE_FORMAT_14);
                    queryWrapper.apply("KPRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", kprq);
                    queryWrapper.orderByAsc(VmsFullOutInvoiceDetails::getFoidid);
                    List<VmsFullOutInvoiceDetails> invoiceList = invoiceDetailsService.list(queryWrapper);
                    if (CollectionUtil.isNotEmpty(invoiceList)) {
                        for (VmsFullOutInvoiceDetails invoice : invoiceList) {
                            // 上传失败
                            LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                            updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey())
                                    .set(VmsFullOutInvoiceDetails::getScjg, e.getMessage())
                                    .set(VmsFullOutInvoiceDetails::getUpdateTime, new Date())
                                    .set(VmsFullOutInvoiceDetails::getUpdateBy, USER_NAME)
                                    .eq(VmsFullOutInvoiceDetails::getFoidid, invoice.getFoidid());
                            invoiceDetailsService.update(updateWrapper);
                        }
                    }
                    success = false;
                }
            }
        }

        long end = System.currentTimeMillis();
        XxlJobHelper.log("{}执行完成，用时：{}ms", LOG_MSG, end - start);
        if (success) {
            return ReturnT.SUCCESS;
        } else {
            XxlJobHelper.handleFail();
            return ReturnT.FAIL;
        }
    }
}
